package com.fitso.model.calculator.nutrition;

import org.springframework.util.Assert;

import com.fitso.model.Constant;
import com.fitso.model.bean.measure.energy.Calorie;
import com.fitso.model.bean.measure.energy.Energy;
import com.fitso.model.bean.measure.mass.Gram;
import com.fitso.model.bean.measure.mass.Mass;
import com.fitso.model.bean.nutrition.Food;
import com.fitso.model.bean.nutrition.Nutrient;

/**
 * <p>
 * Responsible for common nutritional calculations such as energy(calories),
 * mass(grams) and percentage for each consituant part: carb, fat, protein.
 * </p>
 * 
 * @author timothystorm
 */
public class SimpleFoodCalculator implements FoodCalculator {
	/** {@link Food} to calculate on */
	private final Food _food;

	/**
	 * One and only constructor. This class is immutable and therefore very
	 * thread safe. Keep it that way since calculations can become very
	 * processor intensive.
	 * 
	 * @param nutrition
	 *            to calculate on
	 * @param servingSize
	 *            mass/volume serving size
	 * @throws {@link IllegalArgumentException} if nutrition is null
	 */
	public SimpleFoodCalculator(Food nutrition) {
		Assert.notNull(nutrition, "nutrition required");
		_food = nutrition;
	}

	public Double carbEnergyRatio() {
		return calorieRatio(_food.getCarbs());
	}

	public Double carbMassRatio() {
		return massRatio(_food.getCarbs());
	}

	public Double calorieDensityRatio() {

		return _food.getCalories() == null ? 0 : _food.getCalories().divide(totalMass()).getValue().doubleValue();
	}

	public Double fatEnergyRatio() {
		return calorieRatio(_food.getFats());
	}

	public Double fatMassRatio() {
		return massRatio(_food.getFats());
	}

	public Double proteinEnergyRatio() {
		return calorieRatio(_food.getProtein());
	}

	public Double proteinMassRatio() {
		return massRatio(_food.getProtein());
	}

	protected Double calorieRatio(Nutrient nutrient) {
		if (nutrient != null && nutrient.getCalories() != null) {
			return Energy.clone(nutrient.getCalories()).divide(totalEnergy()).doubleValue();
		}
		return Constant.ZERO_DOUBLE;
	}

	protected Double massRatio(final Nutrient nutrient) {
		if (nutrient != null && nutrient.getMass() != null) {
			return Mass.clone(nutrient.getMass()).divide(totalMass()).doubleValue();
		}
		return Constant.ZERO_DOUBLE;
	}

	private Mass totalMass() {
		Gram totalGrams = Gram.zero();
		totalGrams.add(_food.getCarbs() == null ? Gram.zero() : _food.getCarbs().getMass());
		totalGrams.add(_food.getFats() == null ? Gram.zero() : _food.getFats().getMass());
		totalGrams.add(_food.getProtein() == null ? Gram.zero() : _food.getProtein().getMass());
		return totalGrams;
	}

	private Energy totalEnergy() {
		Calorie totalCals = Calorie.zero();
		totalCals.add(_food.getCarbs() == null ? Calorie.zero() : _food.getCarbs().getCalories());
		totalCals.add(_food.getFats() == null ? Calorie.zero() : _food.getFats().getCalories());
		totalCals.add(_food.getProtein() == null ? Calorie.zero() : _food.getProtein().getCalories());
		return totalCals;
	}
}
